package fun.werfamily.wf.goods.core.domain.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import fun.werfamily.wf.base.exception.BaseCoreException;
import fun.werfamily.wf.base.vo.PageInfo;
import fun.werfamily.wf.goods.core.domain.constant.RedisConstant;
import fun.werfamily.wf.goods.core.domain.dto.request.GoodsListReqDTO;
import fun.werfamily.wf.goods.core.domain.dto.request.GoodsSkuDetailReqDTO;
import fun.werfamily.wf.goods.core.domain.dto.response.*;
import fun.werfamily.wf.goods.core.domain.enums.ResponseCodeEnum;
import fun.werfamily.wf.goods.core.domain.service.GoodsService;
import fun.werfamily.wf.goods.core.domain.util.RedisUtil;
import fun.werfamily.wf.goods.core.infrastructure.dataobject.*;
import fun.werfamily.wf.goods.core.infrastructure.mapper.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author Mr.WenMing
 * @date 2022/8/20 16:33
 */
@Slf4j
@Service
public class GoodsServiceImpl implements GoodsService {

    @Resource
    private GoodsSpuMapper goodsSpuMapper;

    @Resource
    private GoodsSkuMapper goodsSkuMapper;

    @Resource
    private GoodsSpuSpecMapper goodsSpuSpecMapper;

    @Resource
    private GoodsSkuSpecValueMapper goodsSkuSpecValueMapper;

    @Resource
    private GoodsAttachmentMapper goodsAttachmentMapper;

    @Resource
    private RedisUtil redisUtil;

    /**
     * 商品列表
     *
     * @param goodsListReqDTO
     * @return
     */
    @Override
    public PageInfo<GoodsSpuDTO> goodsList(GoodsListReqDTO goodsListReqDTO) {
        List<GoodsSpuDTO> goodsSpuDTOList = new ArrayList<>(goodsListReqDTO.getPageSize());
        PageInfo<GoodsSpuDTO> pageInfo = getGoodsCache(goodsListReqDTO);
        if (CollectionUtils.isNotEmpty(pageInfo.getList())) {
            if (StringUtils.isNotBlank(goodsListReqDTO.getKeyWord())) {
                String keyWord = goodsListReqDTO.getKeyWord();
                List<GoodsSpuDTO> list = pageInfo.getList();
                List<GoodsSpuDTO> resultList = list.stream().filter(goodsSpuDTO -> goodsSpuDTO.getSpuName().startsWith(keyWord)).collect(Collectors.toList());
                pageInfo.setList(resultList);
                pageInfo.setTotal(resultList.size());
            }
            return pageInfo;
        }

        if (!redisUtil.keyExists(RedisConstant.GOODS_LIST)) {
            // 加载缓存
            List<GoodsSpuDO> goodsSpecDOS = goodsSpuMapper.listGoodsSpu(goodsListReqDTO.getKeyWord());
            if (CollectionUtils.isEmpty(goodsSpecDOS)) {
                return pageInfo;
            }
            for (GoodsSpuDO goodsSpecDO : goodsSpecDOS) {
                GoodsSpuDTO goodsSpuDTO = new GoodsSpuDTO();
                BeanUtils.copyProperties(goodsSpecDO, goodsSpuDTO);
                goodsSpuDTOList.add(goodsSpuDTO);
            }
            redisUtil.listRightPushAll(RedisConstant.GOODS_LIST, goodsSpuDTOList);
        }
        return getGoodsCache(goodsListReqDTO);
    }

    private PageInfo<GoodsSpuDTO> getGoodsCache(GoodsListReqDTO goodsListReqDTO) {
        int totalPage = 0;
        long start = (goodsListReqDTO.getPageNo() - 1) * goodsListReqDTO.getPageSize();
        long end = goodsListReqDTO.getPageNo() * goodsListReqDTO.getPageSize() - 1;
        PageInfo<GoodsSpuDTO> pageInfo = new PageInfo<>();
        pageInfo.setpageNo(goodsListReqDTO.getPageNo());
        pageInfo.setPageSize(goodsListReqDTO.getPageSize());
        List<GoodsSpuDTO> listByRange = redisUtil.getListByRange(RedisConstant.GOODS_LIST, 0L, -1L, GoodsSpuDTO.class);
        if (StringUtils.isNotBlank(goodsListReqDTO.getCategoryCode())) {
            listByRange = listByRange.stream().filter(goodsSpuDTO -> Objects.equals(goodsSpuDTO.getCategoryCode(), goodsListReqDTO.getCategoryCode())).collect(Collectors.toList());
        }
        Long size = redisUtil.getListSize(RedisConstant.GOODS_LIST);
        pageInfo.setTotal(size.intValue());
        if (CollectionUtils.isNotEmpty(listByRange)) {
            totalPage = (size.intValue() + goodsListReqDTO.getPageSize() - 1) / goodsListReqDTO.getPageSize();
            if (start > listByRange.size() - 1){
                return new PageInfo<>();
            }

            if (end > listByRange.size() - 1){
                end = listByRange.size() - 1;
            }

            pageInfo.setList(listByRange.subList((int) start, (int) (end + 1)));
            pageInfo.setPageCount(totalPage);
            return pageInfo;
        }
        return new PageInfo<>();
    }


    /**
     * 商品详情
     *
     * @param spuCode
     * @return
     */
    @Override
    public GoodsSpuDTO goodsSpuDetail(String spuCode) {
        GoodsSpuDTO goodsSpuDTO = new GoodsSpuDTO();
        List<GoodsSkuDTO> goodsSkuList = new ArrayList<>();
        // 商品的规格
        List<GoodsSpecDTO> specDTOList = new ArrayList<>();
        // sku的规格值list map
        Map<String, List<GoodsSpecValueDTO>> goodsSpecValueMap = new HashMap<>();
        Map<String , String> skuSpecValuesMap = new HashMap<>();
        GoodsSpuDO goodsSpuDO = goodsSpuMapper.getBySpuCode(spuCode);
        if (null == goodsSpuDO) {
            throw new BaseCoreException(ResponseCodeEnum.DATA_IS_EMPTY);
        }
        BeanUtils.copyProperties(goodsSpuDO, goodsSpuDTO);
        // 查询商品附件
        List<GoodsAttachmentDO> goodsAttachmentDOS = goodsAttachmentMapper.listBySpuCodes(Collections.singletonList(spuCode));
        if (!CollectionUtils.isEmpty(goodsAttachmentDOS)) {
            goodsAttachmentDOS = goodsAttachmentDOS.stream().sorted(Comparator.comparing(GoodsAttachmentDO::getSort)).collect(Collectors.toList());
            List<ProductMediaDTO> productMediaDTOList = new ArrayList<>();
            for (GoodsAttachmentDO goodsAttachmentDO : goodsAttachmentDOS) {
                ProductMediaDTO productMediaDTO = new ProductMediaDTO();
                productMediaDTO.setType(goodsAttachmentDO.getMediaType());
                productMediaDTO.setUrl(goodsAttachmentDO.getUrl());
                productMediaDTOList.add(productMediaDTO);
            }
            goodsSpuDTO.setProductMediaDTOList(productMediaDTOList);
        }

        List<GoodsSkuDO> goodsSkuDOS = goodsSkuMapper.listBySpuCodes(Collections.singletonList(goodsSpuDO.getSpuCode()));
        if (CollectionUtils.isEmpty(goodsSkuDOS)) {
            return goodsSpuDTO;
        }
        List<String> skuCodes = goodsSkuDOS.stream().map(GoodsSkuDO::getSkuCode).collect(Collectors.toList());
        // 查询商品规格和规格值
        List<GoodsSkuSpecValueDO> goodsSkuSpecValueDOS = goodsSkuSpecValueMapper.listBySkuCodes(skuCodes);
        // 查询spu的规格
        List<GoodsSpuSpecDO> goodsSpuSpecDOS = goodsSpuSpecMapper.listBySpuCodes(Collections.singletonList(goodsSpuDO.getSpuCode()));

        if (CollectionUtils.isNotEmpty(goodsSkuSpecValueDOS)) {
            Map<String, List<GoodsSkuSpecValueDO>> goodsSpecValuesMap = goodsSkuSpecValueDOS.stream().collect(Collectors.groupingBy(GoodsSkuSpecValueDO::getSkuCode));
            for (String skuCode : skuCodes) {
                List<GoodsSkuSpecValueDO> specValueDOS = goodsSpecValuesMap.get(skuCode);
                if (CollectionUtils.isEmpty(specValueDOS)) {
                    log.warn("sku={}规格不存在", skuCode);
                    continue;
                }
                List<GoodsSpecValueDTO> goodsSpecValueDTOList = new ArrayList<>();
                StringBuilder specValuesBuilder = new StringBuilder();
                for (GoodsSkuSpecValueDO specValueDO : specValueDOS) {
                    GoodsSpecValueDTO goodsSpecValueDTO = new GoodsSpecValueDTO();
                    goodsSpecValueDTO.setSpecCode(specValueDO.getSpecCode());
                    goodsSpecValueDTO.setSpecName(specValueDO.getSpecName());
                    goodsSpecValueDTO.setSpecValue(specValueDO.getSpecValue());
                    goodsSpecValueDTO.setSpecValueCode(specValueDO.getSpecValueCode());
                    specValuesBuilder.append(specValueDO.getSpecCode());
                    specValuesBuilder.append(":");
                    specValuesBuilder.append(specValueDO.getSpecValueCode());
                    specValuesBuilder.append(",");
                    skuSpecValuesMap.put(skuCode, specValuesBuilder.toString());
                    goodsSpecValueDTOList.add(goodsSpecValueDTO);
                }
                goodsSpecValueMap.put(skuCode, goodsSpecValueDTOList);
            }

            // 按规格分组
            Map<String, List<GoodsSkuSpecValueDO>> goodsSkuSpecListMap = goodsSkuSpecValueDOS.stream().collect(Collectors.groupingBy(GoodsSkuSpecValueDO::getSpecCode));
            Set<String> specValueSet = new HashSet<>();
            for (GoodsSpuSpecDO goodsSpuSpecDO : goodsSpuSpecDOS) {
                GoodsSpecDTO goodsSpecDTO = new GoodsSpecDTO();
                String specCode = goodsSpuSpecDO.getSpecCode();
                List<GoodsSpecValueDTO> goodsSpecValueDTOList = new ArrayList<>();
                if (goodsSkuSpecListMap.get(specCode) != null) {
                    List<GoodsSkuSpecValueDO> currentSkuSpecValueDOList = goodsSkuSpecListMap.get(specCode);
                    for (GoodsSkuSpecValueDO goodsSkuSpecValueDO : currentSkuSpecValueDOList) {
                        if (specValueSet.contains(goodsSkuSpecValueDO.getSpecValueCode())) {
                            continue;
                        }
                        GoodsSpecValueDTO goodsSpecValueDTO = new GoodsSpecValueDTO();
                        goodsSpecValueDTO.setSpecCode(specCode);
                        goodsSpecValueDTO.setSpecValue(goodsSkuSpecValueDO.getSpecValue());
                        goodsSpecValueDTO.setSpecValueCode(goodsSkuSpecValueDO.getSpecValueCode());
                        goodsSpecValueDTO.setSpecName(goodsSkuSpecValueDO.getSpecName());
                        goodsSpecValueDTOList.add(goodsSpecValueDTO);
                        specValueSet.add(goodsSkuSpecValueDO.getSpecValueCode());
                    }
                }
                goodsSpecDTO.setSpuCode(goodsSpuSpecDO.getSpuCode());
                goodsSpecDTO.setSpecCode(goodsSpuSpecDO.getSpecCode());
                goodsSpecDTO.setSpecName(goodsSpuSpecDO.getSpecName());
                goodsSpecDTO.setGoodsSpecValueDTOList(goodsSpecValueDTOList);
                specDTOList.add(goodsSpecDTO);
            }
            goodsSpuDTO.setSpecDTOList(specDTOList);
        }

        if (CollectionUtils.isNotEmpty(goodsSkuDOS)) {
            Integer stock = 0;
            for (GoodsSkuDO goodsSkuDO : goodsSkuDOS) {
                GoodsSkuDTO goodsSkuDTO = new GoodsSkuDTO();
                BeanUtils.copyProperties(goodsSkuDO, goodsSkuDTO);
                goodsSkuDTO.setGoodsSpecValueDTOList(goodsSpecValueMap.get(goodsSkuDO.getSkuCode()));
                goodsSkuDTO.setSpecValues(skuSpecValuesMap.get(goodsSkuDO.getSkuCode()));
                goodsSkuList.add(goodsSkuDTO);
                stock += goodsSkuDO.getStock();
            }
            goodsSpuDTO.setSkuList(goodsSkuList);
            goodsSpuDTO.setStock(stock);
        }
        return goodsSpuDTO;
    }

    @Override
    public List<GoodsSkuDTO> goodsSkuDetail(GoodsSkuDetailReqDTO goodsSkuDetailReqDTO) {
        List<GoodsSkuDTO> goodsSkuDTOList = new ArrayList<>();
        if (CollectionUtils.isEmpty(goodsSkuDetailReqDTO.getSkuCodes())) {
            return goodsSkuDTOList;
        }
        List<GoodsSkuDO> goodsSkuDOS = goodsSkuMapper.listBySkuCodes(goodsSkuDetailReqDTO.getSkuCodes());
        // 查询商品规格和规格值
        List<GoodsSkuSpecValueDO> goodsSkuSpecValueDOS = goodsSkuSpecValueMapper.listBySkuCodes(goodsSkuDetailReqDTO.getSkuCodes());
        Map<String, List<GoodsSkuSpecValueDO>> goodsSpecValueDOMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(goodsSkuSpecValueDOS)) {
            goodsSpecValueDOMap = goodsSkuSpecValueDOS.stream().collect(Collectors.groupingBy(GoodsSkuSpecValueDO::getSkuCode));
        }

        if (CollectionUtils.isNotEmpty(goodsSkuDOS)) {
            Map<String, GoodsSpuDO> spuDOMap = new HashMap<>();
            List<String> spuCodes = goodsSkuDOS.stream().map(GoodsSkuDO::getSpuCode).distinct().collect(Collectors.toList());
            List<GoodsSpuDO> goodsSpuDOS = goodsSpuMapper.listBySpuCodes(spuCodes);
            if (CollectionUtils.isNotEmpty(goodsSkuDOS)) {
                spuDOMap = goodsSpuDOS.stream().collect(Collectors.toMap(GoodsSpuDO::getSpuCode, Function.identity(), (o, n) -> n));
            }

            for (GoodsSkuDO goodsSkuDO : goodsSkuDOS) {
                GoodsSkuDTO goodsSkuDTO = new GoodsSkuDTO();
                BeanUtils.copyProperties(goodsSkuDO, goodsSkuDTO);
                GoodsSpuDO goodsSpuDO = spuDOMap.get(goodsSkuDO.getSpuCode());
                if (goodsSpuDO != null) {
                    goodsSkuDTO.setShortImage(goodsSpuDO.getShortImage());
                    goodsSkuDTO.setUnit(goodsSpuDO.getUnit());
                }
                // 商品规格
                List<GoodsSkuSpecValueDO> specValueDOS = goodsSpecValueDOMap.get(goodsSkuDO.getSkuCode());
                if (CollectionUtils.isNotEmpty(specValueDOS)) {
                    List<GoodsSpecValueDTO> goodsSpecValueDTOList = new ArrayList<>();
                    for (GoodsSkuSpecValueDO goodsSkuSpecValueDO : specValueDOS) {
                        GoodsSpecValueDTO goodsSpecValueDTO = new GoodsSpecValueDTO();
                        goodsSpecValueDTO.setSpecValue(goodsSkuSpecValueDO.getSpecValue());
                        goodsSpecValueDTO.setSpecValueCode(goodsSkuSpecValueDO.getSpecValueCode());
                        goodsSpecValueDTO.setSpecName(goodsSkuSpecValueDO.getSpecName());
                        goodsSpecValueDTOList.add(goodsSpecValueDTO);
                    }
                    goodsSkuDTO.setGoodsSpecValueDTOList(goodsSpecValueDTOList);
                }
                goodsSkuDTOList.add(goodsSkuDTO);
            }
        }
        return goodsSkuDTOList;
    }
}
